package com.gin.kotlin.no_gay_alliance.base

import android.util.Log
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.doublePreferencesKey
import androidx.datastore.preferences.core.floatPreferencesKey
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.core.stringSetPreferencesKey
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

/**
 * 委托DataStore到属性
 * @param T 数据类型，可以为： String、 Int、 Long、 Float、 Double、 Boolean、 Set
 * @param defaultValue 该字段的默认值
 * @param name DataStore实例名称，留空时使用引用类的简单名
 * @param key 在DataStore中保存的key，留空时使用字段名
 * @constructor
 */
class DelegateDataStore<T : Any>(
    private val defaultValue: T,
    private val key: String? = null,
    private val name: String? = null
) : ReadWriteProperty<Any, T> {

    override fun getValue(thisRef: Any, property: KProperty<*>): T {
        val storeName = obtainStoreName(thisRef)
        val key = obtainStoreKey(property)
        val datastore = DatastoreUtils.obtain(storeName)
        val preferencesKey = obtainPreferencesKey(key, defaultValue)
        return datastore.getValue(preferencesKey, defaultValue).also {
            Log.d(TAG, "获取委托值 DataStore: $storeName, key: $key, value: $it")
        }
    }

    override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
        val storeName = obtainStoreName(thisRef)
        val key = obtainStoreKey(property)
        val datastore = DatastoreUtils.obtain(storeName)
        val preferencesKey = obtainPreferencesKey(key, defaultValue)
        Log.d(TAG, "设置委托值 DataStore: $storeName, key: $key, value: $value")
        datastore.setValue(preferencesKey, value)
    }

    private fun obtainStoreName(thisRef: Any) = name ?: thisRef.javaClass.simpleName
    private fun obtainStoreKey(property: KProperty<*>) = key ?: property.name
    private fun obtainPreferencesKey(key: String, value: T): Preferences.Key<T> {
        @Suppress("UNCHECKED_CAST") return when (value) {
            is String -> stringPreferencesKey(key)
            is Int -> intPreferencesKey(key)
            is Long -> intPreferencesKey(key)
            is Float -> floatPreferencesKey(key)
            is Double -> doublePreferencesKey(key)
            is Boolean -> booleanPreferencesKey(key)
            is Set<*> -> stringSetPreferencesKey(key)
            else -> throw RuntimeException("不支持的类型:" + value.javaClass.name)
        } as Preferences.Key<T>
    }

    companion object {
        private val TAG = DelegateDataStore::class.java.simpleName
    }
}